/*
**	Command & Conquer Generals Zero Hour(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*************************************************************************** 
 *                                                                         * 
 *                 Project Name : G                                        * 
 *                                                                         * 
 *                    File Name : SLIST.H                                  * 
 *                                                                         * 
 *                   Programmer : Philip W. Gorrow                         * 
 *                                                                         * 
 *                   Start Date : 03/11/97                                 * 
 *                                                                         * 
 *                  Last Update : March 11, 1997 [PWG]                     * 
 *                                                                         * 
 *  The Single List Class is responsible for all management functions that *
 *  can be performed on a singular linked list.  It uses the SLNode class  *
 *  to track the links and maintain a pointer to the object being tracked. *
 *                                                                         *
 *  The singlely linked list class is non destructive.  That is only       * 
 *  pointers to the actual data being stored in the nodes are kept.  The   *
 *  users is responsible for creating the objects to be added and deleting *
 *  the objects once they are removed from the list if they need to be.    *
 *-------------------------------------------------------------------------* 
 * Functions:                                                              * 
 *   *SList<T>::Remove_Head -- Removes the head of the list                * 
 *   *SList<T>::Remove_Tail -- Removes the tail element from the list      * 
 *   SList<T>::Get_Count -- Returns a count of the entries in the list     * 
 *   *SList<T>::Head -- Returns the head node of the list                  * 
 *   *SList<T>::Tail -- Returns the tail node of the list                  * 
 *   SList<T>::Is_Empty -- Returns true if the list is empty               * 
 *   SList<T>::Add_Head -- Adds a node to the head of the list             * 
 *   SList<T>::Add_Head -- Adds a list to to the head of the list          * 
 *   SList<T>::Add_Tail -- Adds a node to the tail of the list             * 
 *   SList<T>::Add_Tail -- Adds a list to the tail of the list             * 
 *   *SList<T>::Find_Node -- returns first node in list matching the input * 
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#ifndef __SLIST_H__
#define __SLIST_H__

#include "slnode.h"

#ifndef NULL
#define NULL 0L
#endif

template <class T>
class SList {
  private:
		SLNode<T> *HeadNode;    // Note: Constructor not called for pointer.
		SLNode<T> *TailNode;

	public:
		//                                  
		// This constructor is inlined because G++ will not create the
		// constructor correctly if it is not defined within the class
		// definition.
		//
		SList(void)
		{
			HeadNode = NULL;
			TailNode = NULL;
		};

		virtual ~SList(void) { Remove_All(); };

		//
		// Returns the current head of the list.  Used to walk the list.
		//
		SLNode<T> *Head(void) const;
		SLNode<T> *Tail(void) const;

		SLNode<T> *Find_Node(T * data) const;

		virtual bool Add_Head(T *data);           // Add   object to head of list
		virtual bool Add_Head(SList<T>& list);    // Add a list  to head of list
		virtual bool Add_Tail(T *data);           // Add   object to tail of list
		virtual bool Add_Tail(SList<T>& list);    // Add a list  to tail of list

		virtual T *Remove_Head(void);             // Remove head node  from list
		virtual T *Remove_Tail(void);             // Remove tail node  from list
		virtual bool Remove(T *element);          // remove an individual element
		virtual void Remove_All(void);            // Remove all  nodes from list

		// Insert before oldnode, if oldnode is NULL then before head node
		virtual bool Insert_Before(T *newnode, T *oldnode =   NULL);

		// Could possibly implement an InsertBefore that operates on a whole list

		// Insert after oldnode, if oldnode is NULL then insert at head
		virtual bool Insert_After(T   *newnode, T *oldnode = NULL);

		// Could possibly implement an InsertAfter that operates on a whole list
		virtual bool Is_Empty(void)   const;      // True if list is empty
		virtual long Get_Count(void) const;    // Returns number of nodes in list
};


/************************************************************************** 
 * SList<T>::Insert_Before -- Inserts entry prior to specified entry      * 
 *                                                                        * 
 * Inserts an entry prior to the specified entry in the  list.  If the    *   
 * specified   entry is null, it will add it prior to the head of the     *
 * list.  Returns true if sucessfully added, false otherwise.             *
 *                                                                        * 
 * INPUT:                                                                 * 
 *                                                                        * 
 * OUTPUT:                                                                * 
 *                                                                        * 
 * WARNINGS:                                                              * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   03/11/1997 PWG : Created.                                            * 
 *========================================================================*/
template<class T>
bool SList<T>::Insert_Before(T *newnode, T   *oldnode)
{
	// if not adding anything then just skip the add.
	if (newnode == NULL)
		return false;

	// if there is no head to the list then add it to head
	if (oldnode == NULL || HeadNode == NULL || HeadNode->Data() == oldnode) {
		return(Add_Head(newnode));
	}

	// now we need to walk the list in an attempt to add the 
	//   node.  since we are a singlely linked list we need 
	//   to stop one prior to the entry.
	SLNode<T> *cur;
	for (cur=HeadNode; cur->Next() && cur->Next()->Data() != oldnode; cur=cur->Next()) {}

	// Verify that we found the entry as it might not have been in the list.
	// Note: Cur will be valid because it wont be assigned unless Next is
	//  valid.
	if (cur->Next() != NULL && cur->Next()->Data() == oldnode) {  
		SLNode<T> *temp	= new SLNode<T> (newnode);
		temp->Set_Next(cur->Next());
		cur->Set_Next(temp);
		return(true);
	}
	return(false);
}


/************************************************************************** 
 * SList<T>::Insert_After -- Inserts an entry after specified entry       * 
 *                                                                        * 
 * Inserts an entry after to the specified entry in the list.  If the     *
 * specified entry is null, it will add it prior to the head of the list. * 
 * Returns true if sucessfully added, false otherwise.                    *
 *                                                                        *
 * INPUT:                                                                 * 
 *                                                                        * 
 * OUTPUT:                                                                * 
 *                                                                        * 
 * WARNINGS:                                                              * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   03/11/1997 PWG : Created.                                            * 
 *========================================================================*/
template<class T>
bool SList<T>::Insert_After(T *newnode, T *oldnode)
{
	if (newnode == NULL)
		return false;

	if (oldnode == NULL || HeadNode == NULL)  {
		return(Add_Head(newnode));
	}

	// Search for oldnode in list
	SLNode<T> *cur;
	for (cur = HeadNode; cur && cur->Data() != oldnode; cur = cur->Next()) {}

	// Did we find the data we want to insert after?
	if (cur != NULL  && cur->Data() == oldnode) {   
		if (cur == TailNode) {        // Inserting after tail
			return(Add_Tail(newnode));
		}

		SLNode<T> *temp		= new SLNode<T>(newnode);
		temp->Set_Next(cur->Next());
		cur->Set_Next(temp);
		return true;
	} 
	return false;
}
/************************************************************************** 
 * SList<T>::Remove_All -- Removes all of the entries in the current list * 
 *                                                                        * 
 * INPUT:                                                                 * 
 *                                                                        * 
 * OUTPUT:                                                                * 
 *                                                                        * 
 * WARNINGS:                                                              * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   03/11/1997 PWG : Created.                                            * 
 *========================================================================*/
template<class T>
void SList<T>::Remove_All(void)
{
	SLNode<T> *next;
	for (SLNode<T> *cur = HeadNode; cur; cur = next) {
		next = cur->Next();
		delete cur;
	}
	HeadNode = TailNode = NULL;
}

/************************************************************************** 
 * SList<T>::Remove -- Removes an element in the list.                    * 
 *                                                                        * 
 * INPUT:                                                                 * 
 *                                                                        * 
 * OUTPUT:  true if element could be removed, false if it could not be    *
 *                                                                        * 
 * WARNINGS:                                                              * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   03/11/1997 PWG : Created.                                            * 
 *========================================================================*/
template<class T>
bool SList<T>::Remove(T *element)
{
	// if not adding anything then just skip the add.
	if (element == NULL || HeadNode == NULL)
		return false;

	// if the head is the element in question remove it
	if (HeadNode->Data() == element) {
		return(Remove_Head() != NULL ? true : false);
	}

	// now we need to walk the list in an attempt to add the 
	//   node.  since we are a singlely linked list we need 
	//   to stop one prior to the entry.
	SLNode<T> *cur;
	for (cur = HeadNode; cur->Next() && cur->Next()->Data() != element; cur=cur->Next()) { }

	// Verify that we found the entry as it might not have been in the list.
	// Note: Cur will be valid because it wont be assigned unless Next is
	//  valid.
	if (cur->Next() != NULL && cur->Next()->Data() == element) {  
		SLNode<T> *temp	= cur->Next();
		cur->Set_Next(temp->Next());
		if (temp == TailNode) TailNode = cur;
		delete temp;
		return true;
	}
	return(false);
}  

/************************************************************************** 
 * *SList<T>::Remove_Head -- Removes the head of the list                 * 
 *                                                                        * 
 * INPUT:                                                                 * 
 *                                                                        * 
 * OUTPUT:                                                                * 
 *                                                                        * 
 * WARNINGS:                                                              * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   03/11/1997 PWG : Created.                                            * 
 *========================================================================*/
template<class T>
T *SList<T>::Remove_Head(void)
{
	if (HeadNode == NULL)      // Should make an assertion here instead!
		return ((T* )NULL);
  
	SLNode<T> *temp = HeadNode;
	HeadNode = HeadNode->Next();

	if (HeadNode == NULL)     // Do we have empty list now?
		TailNode = NULL;

	T *data = temp->Data();
	delete temp;    
	return data;
}

//
// Removes the tail of the list and returns a data pointer to the
// element removed.  Warning!  On a singlely linked list it is 
// slow as hell to remove a tail!  If you need to frequently remove
// tails, then you should consider a doubly linked list.
//

/************************************************************************** 
 * *SList<T>::Remove_Tail -- Removes the tail element from the list       * 
 *                                                                        * 
 * INPUT:		none																		  *
 *                                                                        * 
 * OUTPUT:		returns a pointer to the element removed						  *
 *                                                                        * 
 * WARNINGS:	On a singlely linked list it is slow as hell to remove a   *
 *					tail!  If you need to frequently remove tails, then you 	  *
 *					should consider a doubly linked list.                      * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   03/11/1997 PWG : Created.                                            * 
 *========================================================================*/
template<class T>
T *SList<T>::Remove_Tail(void)
{
	if (HeadNode == NULL)     // Should make an assertion here instead!
		return ((T *)NULL);

	T* data = TailNode->Data();
	return (Remove(data) ? data : (T*)NULL);
}


/************************************************************************** 
 * SList<T>::Get_Count -- Returns a count of the entries in the list      * 
 *                                                                        * 
 * INPUT:                                                                 * 
 *                                                                        * 
 * OUTPUT:                                                                * 
 *                                                                        * 
 * WARNINGS:                                                              * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   03/11/1997 PWG : Created.                                            * 
 *========================================================================*/
template<class T>
inline long SList<T>::Get_Count(void) const
{
	long count = 0;
	for (SLNode<T> *cur = HeadNode; cur; cur = cur->Next())
		count++;
	return count;
}


/************************************************************************** 
 * *SList<T>::Head -- Returns the head node of the list                   * 
 *                                                                        * 
 * INPUT:                                                                 * 
 *                                                                        * 
 * OUTPUT:                                                                * 
 *                                                                        * 
 * WARNINGS:                                                              * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   03/11/1997 PWG : Created.                                            * 
 *========================================================================*/
template<class T>
inline SLNode<T> *SList<T>::Head(void) const
{
	return(HeadNode);
}

/************************************************************************** 
 * *SList<T>::Tail -- Returns the tail node of the list                   * 
 *                                                                        * 
 * INPUT:                                                                 * 
 *                                                                        * 
 * OUTPUT:                                                                * 
 *                                                                        * 
 * WARNINGS:                                                              * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   03/11/1997 PWG : Created.                                            * 
 *========================================================================*/
template<class T>
inline SLNode<T> *SList<T>::Tail(void) const
{
	return(TailNode);
}

/************************************************************************** 
 * SList<T>::Is_Empty -- Returns true if the list is empty                * 
 *                                                                        * 
 * INPUT:                                                                 * 
 *                                                                        * 
 * OUTPUT:                                                                * 
 *                                                                        * 
 * WARNINGS:                                                              * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   03/11/1997 PWG : Created.                                            * 
 *========================================================================*/
template<class T>
inline bool SList<T>::Is_Empty(void) const
{
	return( HeadNode == NULL ? true : false);
}


/************************************************************************** 
 * SList<T>::Add_Head -- Adds a node to the head of the list              * 
 *                                                                        * 
 * INPUT:                                                                 * 
 *                                                                        * 
 * OUTPUT:                                                                * 
 *                                                                        * 
 * WARNINGS:                                                              * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   03/11/1997 PWG : Created.                                            * 
 *========================================================================*/
template<class T>
bool SList<T>::Add_Head(T *data)
{
	// we don't deal with lists that point to nothing
	if (!data) return false;

	SLNode<T> *temp			= new SLNode<T>(data);
	temp->Set_Next(HeadNode);
	HeadNode						= temp;
	if (!TailNode) TailNode	= temp;
	return true;
}


/************************************************************************** 
 * SList<T>::Add_Head -- Adds a list to to the head of the list           * 
 *                                                                        * 
 * INPUT:                                                                 * 
 *                                                                        * 
 * OUTPUT:                                                                * 
 *                                                                        * 
 * WARNINGS:                                                              * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   03/11/1997 PWG : Created.                                            * 
 *========================================================================*/
template<class T>
bool SList<T>::Add_Head(SList<T>& list)
{
	if (list.HeadNode == NULL) return false;

	// Save point for initial add of element.
	SLNode<T> *addpoint = NULL;

	// We traverse list backwards so nodes are added in right order.
	for (SLNode<T> *cur = list.HeadNode; cur; cur = cur->Next()) 
	if (addpoint) {
		SLNode<T> *temp   = new SLNode<T>(cur->Data());
		temp->Set_Next(addpoint->Next());
		addpoint->Set_Next(temp);
		addpoint = temp;
	} else {
		Add_Head(cur->Data());
		addpoint = HeadNode;
	}
	return true;
}

/************************************************************************** 
 * SList<T>::Add_Tail -- Adds a node to the tail of the list              * 
 *                                                                        * 
 * INPUT:                                                                 * 
 *                                                                        * 
 * OUTPUT:                                                                * 
 *                                                                        * 
 * WARNINGS:                                                              * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   03/11/1997 PWG : Created.                                            * 
 *========================================================================*/
template<class T>
bool SList<T>::Add_Tail(T *data)
{
	if (data == NULL) return false;

	SLNode<T> *temp = new SLNode<T> (data);

	if (HeadNode == NULL) {				// empty list
		HeadNode = TailNode	= temp;
	} else {									// non-empty list
		TailNode->Set_Next(temp);
		TailNode					= temp;
	}
	return true;
}

/************************************************************************** 
 * SList<T>::Add_Tail -- Adds a list to the tail of the list              * 
 *                                                                        * 
 * INPUT:                                                                 * 
 *                                                                        * 
 * OUTPUT:                                                                * 
 *                                                                        * 
 * WARNINGS:                                                              * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   03/11/1997 PWG : Created.                                            * 
 *========================================================================*/
template<class T>
bool SList<T>::Add_Tail(SList<T>& list)
{
	if (list.HeadNode == NULL) return false;

	for (SLNode<T> *cur = list.HeadNode; cur; cur = cur->Next()) 
		Add_Tail(cur->Data());
	return true;
}
 

/************************************************************************** 
 * *SList<T>::Find_Node -- returns first node in list matching the input  * 
 *                                                                        * 
 * INPUT:                                                                 * 
 *                                                                        * 
 * OUTPUT:                                                                * 
 *                                                                        * 
 * WARNINGS:                                                              * 
 *                                                                        * 
 * HISTORY:                                                               * 
 *   08/22/1997 GH  : Created.                                            * 
 *========================================================================*/
template<class T>
inline SLNode<T> *SList<T>::Find_Node(T * data) const
{
	SLNode<T> * cur;

	for (cur = HeadNode; cur && cur->Data() != data; cur = cur->Next());
	
	return cur;
}

#endif
